package com.rui.visitor.main;

import com.rui.visitor.model.Report;
import com.rui.visitor.obj.*;

import java.util.ArrayList;
import java.util.List;

/**
 * 访问者模式（Visitor Pattern）
 * <p>
 * <p>
 * 访问者模式是一种将数据结构与数据操作分离的设计模式。是指封装一些作用于某种数据结构中的各元素的操作。
 * <p>
 * 特征：可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
 * <p>
 * 访问者模式包含以下主要角色:
 * 抽象访问者（Visitor）角色：定义了对每一个元素 （Element） 访问的行为，它的参数就是可以访问的元素，它的方法个数理论上来讲与元素类个数（Element的实现类个数）是一样的，从这点不难看出，访问者模式要求元素类的个数不能改变。
 * 具体访问者（ConcreteVisitor）角色：给出对每一个元素类访问时所产生的具体行为。
 * 抽象元素（Element）角色：定义了一个接受访问者的方法（ accept ），其意义是指，每一个元素都要可以被访问者访问。
 * 具体元素（ConcreteElement）角色： 提供接受访问方法的具体实现，而这个具体的实现，通常情况下是使用访问者提供的访问该元素类的方法。
 * 对象结构（Object Structure）角色：定义当中所提到的对象结构，对象结构是一个抽象表述，具体点可以理解为一个具有容器性质或者复合对象特性的类，它会含有一组元素（ Element ），并且可以迭代这些元素，供访问者访问。
 * <p>
 * <p>
 * 适用场景：
 * 数据结构稳定，作用于数据结构的操作经常变化的场景。
 * 需要数据结构与数据操作分离的场景。
 * 需要对不同数据类型（元素）进行操作，而不使用分支判断具体类型的场景。
 * <p>
 * 优点：
 * 解耦了数据结构与数据操作，使得操作集合可以独立变化。
 * 扩展性好：可以通过扩展访问者角色，实现对数据集的不同操作。
 * 元素具体类型并非单一，访问者均可操作。
 * 各角色职责分离，符合单一职责原则。
 * <p>
 * 缺点：
 * 无法增加元素类型：若系统数据结构对象易于变化，经常有新的数据对象增加进来，则访问者类必须增加对应元素类型的操作，违背了开闭原则。
 * 具体元素变更困难：具体元素增加属性，删除属性等操作会导致对应的访问者类需要进行相应的修改，尤其当有大量访问者类时，修改访问太大。
 * 违背依赖倒置原则：为了达到“区别对待”，访问者依赖的是具体元素类型，而不是抽象。
 *
 * @author ZhangRui
 * @date 2023/03/03 17:03
 **/
public class Main {

    public static void main(String[] args) {

        List<Employee> employeeList = new ArrayList<>();
        employeeList.add(new Engineer("工程师A"));
        employeeList.add(new Engineer("工程师B"));
        employeeList.add(new Pm("项目经理A"));
        employeeList.add(new Engineer("工程师C"));
        employeeList.add(new Engineer("工程师D"));
        employeeList.add(new Pm("项目经理B"));

        Report report = new Report(employeeList);
        System.out.println("=============CEO==============");
        report.showReport(new CeoVisitor());
        System.out.println("=============CTO==============");
        report.showReport(new CtoVisitor());

//        =============CEO==============
//        工程师AKPI为:9
//        工程师BKPI为:4
//        项目经理AKPI为:6
//        工程师CKPI为:7
//        工程师DKPI为:5
//        项目经理BKPI为:3
//        =============CTO==============
//        工程师A工作内容:7210行代码
//        工程师B工作内容:9234行代码
//        项目经理A工作内容:1个项目
//        工程师C工作内容:9263行代码
//        工程师D工作内容:4085行代码
//        项目经理B工作内容:2个项目
    }
}
